#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
#include<sys/wait.h>
#include<iostream>

// 全局变量
#define HOST_NAME 256
#define FORMAT "[%s@%s:%s]# "
#define COMMANDLINE 256
#define ARGV_MAX 128
char hostName[HOST_NAME];
int g_argc = 0;
char* g_argv[ARGV_MAX];
int lastcode = 0;
#define MAX_ENVS 100
char *g_env[MAX_ENVS];
int g_envs = 0;

// 接口
// 用户名
const char* getUser()
{
	char* name = getenv("USER");
	return name == NULL ? "None" : name;
}
// 当前路径
const char* getPwd()
{
	char* pwd = getenv("PWD");
	return pwd == NULL ? "None" : pwd;
}
// 主机
const char* getHostName()
{
	if (gethostname(hostName,sizeof(hostName))<0)
	{
		perror("没有得到主机名!\n");
		exit(1);
	}
	return hostName;
}
// home路径
const char* getHome()
{
	char* home = getenv("HOME");
	return home == NULL ? "" :home ; 
}
const char* getOldPwd()
{
	char* oldPwd = getenv("OLDPWD");
	return oldPwd == NULL ? "" : oldPwd;
}

void MakeCommandLine(char cmd_prompt[],size_t size)
{
	snprintf(cmd_prompt,size,FORMAT,getUser(),getPwd(),getHostName());
}

void PrintCommandLine()
{
	char prompt[COMMANDLINE];
	MakeCommandLine(prompt,COMMANDLINE);
	printf("%s",prompt);
	fflush(stdout);
}

bool GetCommandLine(char *out,size_t size)
{
	char *c = fgets(out,size,stdin);
	//printf("%s",out);
	if (c==NULL) return false;
	out[strlen(out)-1] = '\0';	
	if (strlen(out)==0) return false;
	return true;
}
bool CommandParse(char* commandLine)
{
#define SEP " "
	g_argc = 0;
	g_argv[g_argc++] = strtok(commandLine,SEP);
	while ((bool)(g_argv[g_argc++]=strtok(NULL,SEP)));
	g_argc--;// 不加不出现段错误 越界访问
	return true;

}
void PrintArgv()
{
	for(int i = 0;i<g_argc;i++)
	{
		printf("%s\n",g_argv[i]);
	}
}
int Execute()
{
	// 创建子进程
	pid_t id = fork();
	if (id == 0)
	{
		execvp(g_argv[0],g_argv);
		exit(1);
	}
	int status = 0;
    // father
    pid_t rid = waitpid(id, &status, 0);
    if(rid > 0)
    {
        lastcode = WEXITSTATUS(status);
    }
	return 0;
}
bool Cd()
{
    // 保存当前目录作为 OLDPWD
    char oldPwd[COMMANDLINE];
    if (getcwd(oldPwd, sizeof(oldPwd)) == NULL) {
        perror("getcwd");
        return false;
    }

    // 1. cd 无参数：跳到 HOME
    if (g_argc == 1)
    {
        const char* home = getHome();
        if (home == NULL || strlen(home) == 0) {
            fprintf(stderr, "cd: HOME not set\n");
            return false;
        }
        if (chdir(home) != 0) {
            perror("cd");
            return false;
        }
    }
    else
    {
        const char* where = g_argv[1];
        
        // ~ 返回到家目录
        if (strcmp(where, "~") == 0)
        {
            const char* home = getHome();
            if (home == NULL || strlen(home) == 0) {
                fprintf(stderr, "cd: HOME not set\n");
                return false;
            }
            if (chdir(home) != 0) {
                perror("cd");
                return false;
            }
        }
        // - 返回到上一个路径
        else if (strcmp(where, "-") == 0)
        {
            const char* envOldPwd = getOldPwd();
            if (envOldPwd == NULL || strlen(envOldPwd) == 0) {
                fprintf(stderr, "cd: OLDPWD not set\n");
                return false;
            }
            if (chdir(envOldPwd) != 0) {
                perror("cd");
                return false;
            }
            // 显示新目录（符合 bash 行为）
            char cwd[COMMANDLINE];
            getcwd(cwd, sizeof(cwd));
            printf("%s\n", cwd);
        }
        // . 保持当前目录
        else if (strcmp(where, ".") == 0)
        {
            // 什么都不做
        }
        // .. 跳到父目录
        else if (strcmp(where, "..") == 0)
        {
            if (chdir("..") != 0) {
                perror("cd");
                return false;
            }
        }
        // 其他路径
        else
        {
            if (chdir(where) != 0) {
                perror("cd");
                return false;
            }
        }
    }

    // 更新环境变量
    char newPwd[COMMANDLINE];
    if (getcwd(newPwd, sizeof(newPwd)) == NULL) {
        perror("getcwd");
        return false;
    }
    setenv("OLDPWD", oldPwd, 1);
    setenv("PWD", newPwd, 1);
    
    return true;
}
void Echo()
{
    if(g_argc == 2)
    {
        // echo "hello world"
        // echo $?
        // echo $PATH
        std::string opt = g_argv[1];
        if(opt == "$?")
        {
            std::cout << lastcode << std::endl;
            lastcode = 0;
        }
        else if(opt[0] == '$')
        {
            std::string env_name = opt.substr(1);
            const char *env_value = getenv(env_name.c_str());
            if(env_value)
                std::cout << env_value << std::endl;
        }
        else
        {
            std::cout << opt << std::endl;
        }
    }
}
bool CheckAndExecBuiltin()
{
	// 1. 获得命令
	char* command = g_argv[0];
	if (strcmp(command , "cd")==0)
	{
		Cd();
		return true;
	}
	else if (strcmp(command,"echo")==0)
	{
		Echo();
		return true;
	}
	// 等等
	return false;
}
void InitEnv()
{
	extern char** environ;
	memset(g_env,0,sizeof(g_env));
	g_envs = 0;

	// 从父进程得到环境变量
	for(int i = 0;environ[i];i++)
	{
		g_env[i] = (char*)malloc(strlen(environ[i])+1);
		strcpy(g_env[i],environ[i]);
		g_envs++;	
	}
	g_env[g_envs++] = (char*)"HAHA=123456";
	g_env[g_envs] = NULL;

	// 导出环境变量
	for(int i = 0;g_env[i];i++)
	{
		putenv(g_env[i]);
	}
	environ = g_env;
}
void Cleanup()
{
    for(int i = 0; i < g_envs; i++) {
        free(g_env[i]);
    }
}

int main()
{
	InitEnv();
	while(1)
	{
		// 1. 输入命令行参数
		PrintCommandLine();
		// 2. 获得命令行
		char commandLine[COMMANDLINE];
		if(!GetCommandLine(commandLine,COMMANDLINE))
			continue;
		
		// 3. 解析命令行
		if (!CommandParse(commandLine))
			continue;
//		PrintArgv();	
		// 3.1. 是否是内建命令
		if (CheckAndExecBuiltin())
			continue;
		// 4. 执行命令行
		Execute();		
	}
	Cleanup();
	return 0;
}

